package org.wak.dialog.sci
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	
	import org.wak.character.AdventureCharacter;
	import org.wak.dialog.AdventureDialog;
	import org.wak.dialog.DialogManager;
	import org.wak.dialog.IDialogsController;
	import org.wak.dialog.SayItem;
	import org.wak.dialog.Topic;
	import org.wak.dialog.TopicActions;
	import org.wak.dialog.event.PuzzleActionEvent;
	import org.wak.dialog.event.TextSelectedEvent;
	import org.wak.gui.GuiManager;
	import org.wak.main.AdventureMaster;
	import org.wak.scene.SceneManager;
	import org.wak.utils.IIterator;
	import org.wak.utils.Utils;

	public class SciDialogController extends Sprite implements IDialogsController
	{
		private var mDialogLayer:Sprite = null ;
		
		private var mDialogsMenuArray:Array = null ;
		
		// local reference to the gui manager.
		private var mGuiMngr:GuiManager = null ;
		
		// local reference to the scene manager
		private var mSceneMngr:SceneManager = null ;
		
		// local reference to the dialog manager
		private var mDialogMngr:DialogManager = null ;
		
		// local reference to the resources.
		private var mResourceManager:Class = null ;
		
		private var mStageWidth:Number = 0 ;
		private var mStageHeight:Number = 0 ;
		
			
		// last dialog started with StartDialog
		private var mCurrentDialog:AdventureDialog = null ;
		
		// previous last dialog started with StartDialog
		private var mPreviousDialog:AdventureDialog = null ;
		
		// Local copy of the player's character id
		private var mPlayerCharId:String = "" ;
		
		// the current playing topic
		private var mPlayingTopic:Topic = null ;
		
		// current menu dialog
		private var mCurrentDialogMenu:SciDialogMenu = null ;
		
		// previous menu dialog
		private var mPreviousDialogMenu:SciDialogMenu = null ;
		
		
		// settings loaded vars.//
		
		
			//vars for dialog text display.
		private var mConfDTextEmbedFonts:Boolean = false ;
		
		private var mConfDTextFont:String = "" ;
		
		private var mConfDTextSize:Number = 14 ;
		
		private var mConfDTextBold:Boolean = false ;
		
		private var mConfDTextShadow:Boolean = false ;
		
		private var mConfDTextLeftMargin:Number = 0 ;
		private var mConfDTextTopMargin:Number = 0 ;
		
		// vertical coordinate of the Dialog text display window.
		private var mConfTextYCoordinate:int = 20 ;
		
		private var mConfTextBgId:String = "" ;
			
		// Color of the text display background.
		private var mConfTextDisplayColor:uint = 0xFBE5A5 ;
		
		// width of the text displays.
		private var mConfTDisplayWidth:Number = 300 ;
		
		// height of the text displays.
		private var mConfTDisplayHeight:Number = 100 ;
		
		private var mConfTextBg:DisplayObject = null;
		
		private var mConfTextInfoColor:uint = 0x000000;
		
		private var mConfDefaultBgMenuWidth:Number = 200 ;
		
		private var mConfDefaultBgMenuHeight:Number = 100 ;
		
		
		// vars of dialog menu.
		private var mConfMenuOptionWidth:Number = 100 ;
		private var mConfMenuOptionHeight:Number = 10 ;
		
		private var mConfMenuFontUpColor:uint = 0xFFFFFF ;
		private var mConfMenuFontOverColor:uint = 0xFFFFFF ;
		
		private var mConfMenuEmbedFonts:Boolean = false ;
		
		private var mConfMenuFont:String = "" ;
		
		private var mConfMenuFontSize:Number = 10 ;
		
		private var mConfMenuBold:Boolean = false ;
		
		private var mConfMenuBulletId:String = "" ;
		
		private var mConfMenuBulletMargin:Number = 1 ;
		
		private var mConfMenuLeftMargin:Number = 1 ;
		
		private var mConfMenuBgId:String = "" ;
		private var mConfMenuBackground:DisplayObject = null ;
		
		private var mConfMenuBgColor:uint = 0xFFFFFF ;
		
		private var mConfMenuBgWidth:Number = 300 ;
		private var mConfMenuBgHeight:Number = 200 ;
		
		
		/**
		 * Constructor 
		 * @param pLayer The dialogs layer.
		 * @param pSettings XMl with the dialogs settings.
		 * 
		 */		
		public function SciDialogController(pLayer:Sprite, pSettings:XML)
		{
			super();
			
			mDialogsMenuArray = new Array();
			mResourceManager = AdventureMaster.Resources ;
			mDialogLayer = pLayer ;
			LoadSettings(pSettings);
		}
		
		public function Initialize():void
		{
			mGuiMngr = AdventureMaster.GuiMngr ;
			mSceneMngr = AdventureMaster.SceneMngr ;
			mDialogMngr = AdventureMaster.DialogMngr ;
			
			mStageWidth = mDialogLayer.stage.stageWidth ;
			mStageHeight = mDialogLayer.stage.stageHeight ;
			
			
			mPlayerCharId = AdventureMaster.defaultPlayerCharacterId ;
			
			//mConfTextBg = new mResourceManager["dialogBg"];
			//this.addEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
		}
		
		/**
		 * Load the settings of the dialogs using the parameters in pSettings 
		 * @param pSettings XML with the settings.
		 * 
		 */		
		protected function LoadSettings( pSettings:XML ):void
		{
			mConfDTextEmbedFonts = pSettings.SpeakText.UseEmbedFont == "true"? true : false ;
		
			mConfDTextFont = pSettings.SpeakText.TextFont ;
			
			mConfDTextSize = pSettings.SpeakText.TextSize ;
			
			mConfDTextBold = pSettings.SpeakText.Bold == "true"? true : false ;
			
			mConfDTextShadow = pSettings.SpeakText.DropShadow == "true"? true : false ;
			
			mConfTextYCoordinate = pSettings.SpeakText.WindowY ;
			
			mConfTextBgId = pSettings.SpeakText.Background ;
				
			mConfTextDisplayColor = uint("0x"+pSettings.SpeakText.BackgroundColor) ;
			mConfTDisplayWidth = pSettings.SpeakText.Width ;
			mConfTDisplayHeight = pSettings.SpeakText.Height ;
			
			if(mConfTextBgId != "")
				mConfTextBg = new mResourceManager[mConfTextBgId] ;
				
			mConfTextInfoColor = uint("0x"+pSettings.SpeakText.DisplayInfoColor) ;
			
			mConfDTextLeftMargin = pSettings.SpeakText.LeftMargin ;
			mConfDTextTopMargin = pSettings.SpeakText.TopMargin ;
			
			// Config dialog menu.
			
			mConfMenuOptionWidth = pSettings.DialogMenu.OptionWidth ;
			mConfMenuOptionHeight = pSettings.DialogMenu.OptionHeight ;
			
			mConfMenuFontUpColor = uint( "0x"+pSettings.DialogMenu.FontColor );
			mConfMenuFontOverColor = uint( "0x"+pSettings.DialogMenu.FontOverColor );
			
			mConfMenuEmbedFonts = pSettings.DialogMenu.UseEmbedFont == "true" ? true : false ;
			
			mConfMenuFont = pSettings.DialogMenu.TextFont;
			
			mConfMenuFontSize = pSettings.DialogMenu.TextSize;
			
			mConfMenuBold = pSettings.DialogMenu.Bold == "true" ? true : false ;
			
			mConfMenuBulletId = pSettings.DialogMenu.Bullet ;
			
			mConfMenuBulletMargin = pSettings.DialogMenu.BulletMargin ;
			
			mConfMenuLeftMargin = pSettings.DialogMenu.LeftMargin ;
			
			mConfMenuBgId = pSettings.DialogMenu.Background ;
			if(mConfMenuBgId != "")
				mConfMenuBackground = new mResourceManager[mConfMenuBgId] ;
			
			
			mConfMenuBgColor = uint( "0x"+pSettings.DialogMenu.BackgroundColor ) ;
			
			mConfMenuBgWidth = pSettings.DialogMenu.Width ;
			mConfMenuBgHeight = pSettings.DialogMenu.Height ;
			
				
			
			
		}
		
		public function get display():DisplayObject
		{
			return this;
		}
		
		/**
		 * @private
		 */
		private function RunAction(pTopic:Topic):void
		{
			if(pTopic == null)
				return ;
				
			switch( pTopic.action )
			{
				case TopicActions.EXIT:
					StopDialog();
				break;
				case TopicActions.GOTO:	
					GotoDialog( pTopic.target )
				break;
				case TopicActions.BACK:
					GoBackDialog();
				break;
				case TopicActions.ACTIVATE:
					ActivateOption(pTopic.target);
				break;
				case TopicActions.ACTION:
					RunTopicAction(pTopic.target);
				break;
			
			}
		}
		
		/**
		 * @inheritDoc
		 */	
		public function ActivateOption(pTopicId:String):void
		{
			mCurrentDialogMenu.SetOptionVisible(pTopicId,true);
		}
		
		/**
		 * @private
		 */	
		private function RunTopicAction( pFuncName:String ):void
		{
			var fEvent:Event = new PuzzleActionEvent( PuzzleActionEvent.PUZZLE_ACTION_EVENT, pFuncName);
			this.dispatchEvent(fEvent);
		}
		
		/**
		 * Force to stop any dialog playing. 
		 * 
		 */		
		private function StopDialog():void
		{
			if(mCurrentDialogMenu != null)
			{
				if( this.contains(mCurrentDialogMenu) )
					this.removeChild(mCurrentDialogMenu);
			}
			
			mCurrentDialog = null ;
			mGuiMngr.enabled = true ;
			mSceneMngr.enabled = true ;
		}
		
		/**
		 * @private
		 */
		private function GotoDialog(pDialogId:String):void
		{
			var fDialog:AdventureDialog = mDialogMngr.GetDialog( pDialogId );
			StartDialog(fDialog);
		}
		
			/**
		 * @private
		 */
		private function GoBackDialog():void
		{
			if( mPreviousDialog == null )
				return ;
			
			if(mCurrentDialog != null)
			{
				mCurrentDialogMenu.removeEventListener( SciDialogMenu.TEXT_SELECTED, OnDialogOptionSelected );
				if(this.contains( mCurrentDialogMenu) )
					this.removeChild(mCurrentDialogMenu);				
			}
				
			//StartDialog(mPreviousDialog);
			var fBackDialog:AdventureDialog = mPreviousDialog ;
			
			mPreviousDialog = mCurrentDialog ;
			mCurrentDialog = fBackDialog ;
			
			StartDialogAfterEntryTopic();
		}
		
		
		public function StartDialog(pDialog:AdventureDialog):void
		{
			
			if(mCurrentDialog != null)
			{
				mCurrentDialogMenu.removeEventListener( SciDialogMenu.TEXT_SELECTED, OnDialogOptionSelected );
				if(this.contains( mCurrentDialogMenu) )
					this.removeChild(mCurrentDialogMenu);				
			}
			
			
			mGuiMngr.enabled = false ;
			mSceneMngr.enabled = false ;
			
			mPreviousDialog = mCurrentDialog ;
			mCurrentDialog = pDialog ;
			
			// if the entry topic is just for one time only.
			if(mCurrentDialog.startupTopic.onlyOnce)
			{ 
				if(!mCurrentDialog.startupTopic.played)
				{
					PlayTopic(mCurrentDialog.startupTopic,OnEntryTopicSayCompleted );
				}
				else
				{
					if(mCurrentDialog.isPresent( mPlayerCharId ))
						OnEntryTopicSayCompleted();
					else
						StopDialog();
				}
			}
			else
			{
				PlayTopic(mCurrentDialog.startupTopic,OnEntryTopicSayCompleted );
			}
		}
		
		private var mOnCharacterSayCompleted:Function = null ;
		
		
		/**
		 * Makes a character say something.
		 * @param pChar The speaker character.
		 * @param pTextToSay The text that the character will way.
		 * @param pOnComplete Callback function called when the character finished to talk.
		 * 
		 */		
		public function CharacterSay(pChar:AdventureCharacter, pTextToSay:String, pOnComplete:Function=null):void
		{
			var fNewText:SciDialogTextDisplay = new SciDialogTextDisplay(pTextToSay,pChar.characterDisplay.portrait,mConfTextBg,false,mConfDTextFont,mConfDTextSize,pChar.speechColor,mConfDTextBold);
			
			mOnCharacterSayCompleted = pOnComplete ;
			
			fNewText.bgColor = mConfTextDisplayColor ;
			fNewText.SetSize( mConfTDisplayWidth, mConfTDisplayHeight);
			fNewText.addEventListener(Event.COMPLETE,OnTextDisplayCompleted,false,0,true);
						
			this.addChild( fNewText );
			fNewText.leftMargin = mConfDTextLeftMargin ;
			fNewText.topMargin = mConfDTextTopMargin ;
			
			fNewText.x = Utils.AlignCenter(fNewText.width, mStageWidth);
			fNewText.y = mConfTextYCoordinate ;
			
		}
		
		
		private var mCurrentSayIterator:IIterator = null ;
		/**
		 * Start to play a dialog topic. 
		 * @param pTopic the topic to play
		 * @param pOnCompleteFunc callaback function called when the topic finish.
		 * 
		 */		
		public function PlayTopic(pTopic:Topic, pOnCompleteFunc:Function):void
		{
			mCurrentSayIterator = pTopic.GetSayItems() ;
			
			if(!(mCurrentSayIterator.hasNext()))
				return ;
			
			pTopic.played = true ;
			mPlayingTopic = pTopic ;	
			SetDialogPanelVisible(false);
			
			var fSayItem:SayItem = mCurrentSayIterator.next() as SayItem;
			var fSpeakerChar:AdventureCharacter = null ; 
			
			if(fSayItem.speakerId == mPlayerCharId)
			{
				if( pTopic.say )
				{
					fSpeakerChar = AdventureMaster.CharactersMngr.GetCharacter(fSayItem.speakerId) ;
					CharacterSay(fSpeakerChar, fSayItem.text, pOnCompleteFunc );
				}
				else
				{
					if(!(mCurrentSayIterator.hasNext()))
					{
						RunAction(pTopic);
						return ;
					}
						
					fSayItem = mCurrentSayIterator.next() as SayItem;
					fSpeakerChar = AdventureMaster.CharactersMngr.GetCharacter(fSayItem.speakerId) ;
					CharacterSay(fSpeakerChar, fSayItem.text, pOnCompleteFunc );
				}
			}
			else
			{
				fSpeakerChar = AdventureMaster.CharactersMngr.GetCharacter(fSayItem.speakerId) ;
				CharacterSay(fSpeakerChar, fSayItem.text, pOnCompleteFunc );
			}
			
		}
		
		/**
		 * @private
		 */
		private function OnEntryTopicSayCompleted():void
		{
			if(!(mCurrentSayIterator.hasNext()))
			{
				RunAction(mPlayingTopic);
				mPlayingTopic = null ;
				StartDialogAfterEntryTopic();
				return ;
			}
			var fSayItem:SayItem = mCurrentSayIterator.next() as SayItem ;
			var fSpeakerChar:AdventureCharacter = AdventureMaster.CharactersMngr.GetCharacter(fSayItem.speakerId) ;
			CharacterSay(fSpeakerChar, fSayItem.text, OnEntryTopicSayCompleted ); 
		
		}
		
		/**
		 * @private
		 */
		private function StartDialogAfterEntryTopic():void
		{
			/*
			var fDialogMenu:SciDialogMenu = mDialogsMenuArray[mCurrentDialog.dialogId] as SciDialogMenu;
			if(fDialogMenu == null)
			{
				fDialogMenu = new SciDialogMenu(mCurrentDialog, mConfMenuBackground, mConfMenuOptionWidth,mConfMenuOptionHeight,
									mConfMenuFont,mConfMenuFontUpColor,mConfMenuFontOverColor,mConfMenuFontSize,mConfMenuBold, mConfMenuEmbedFonts);
					
				mDialogsMenuArray[mCurrentDialog.dialogId] = fDialogMenu ;
				
			}
			*/
			
			if(mCurrentDialog == null)
				return ;
			
			var fDialogMenu:SciDialogMenu = CreateDialogMenu(mCurrentDialog.dialogId);
			
			mPreviousDialogMenu = mCurrentDialogMenu ;
			mCurrentDialogMenu = fDialogMenu ;
			mCurrentDialogMenu.addEventListener( SciDialogMenu.TEXT_SELECTED, OnDialogOptionSelected );
			
			fDialogMenu.SetDefaultBgSize(mConfDefaultBgMenuWidth,mConfDefaultBgMenuHeight);
			
			mCurrentDialogMenu.SetDefaultBgColor( mConfMenuBgColor );
			mCurrentDialogMenu.SetDefaultBgSize(mConfMenuBgWidth, mConfMenuBgHeight);
			mCurrentDialogMenu.SetMargins( mConfMenuBulletMargin, mConfMenuLeftMargin);
			mCurrentDialogMenu.SetBulletAsset( mResourceManager[ mConfMenuBulletId ] );
			
			// Add the dialog panel.
			this.addChild(mCurrentDialogMenu);
			
			fDialogMenu.y = Utils.AlignCenter(fDialogMenu.height, mStageHeight) ;
			fDialogMenu.x = Utils.AlignCenter(fDialogMenu.width, mStageWidth) ;
			
			SetDialogPanelVisible(true);
		}
		
		protected function CreateDialogMenu(pDialogId:String):SciDialogMenu
		{
			var fDialogMenu:SciDialogMenu = mDialogsMenuArray[pDialogId] as SciDialogMenu;
			var fAdvDialog:AdventureDialog = mDialogMngr.GetDialog(pDialogId);
			
			if((fDialogMenu == null) && (fAdvDialog != null))
			{
				fDialogMenu = new SciDialogMenu(fAdvDialog, mConfMenuBackground, mConfMenuOptionWidth,mConfMenuOptionHeight,
									mConfMenuFont,mConfMenuFontUpColor,mConfMenuFontOverColor,mConfMenuFontSize,mConfMenuBold, mConfMenuEmbedFonts);
					
				mDialogsMenuArray[pDialogId] = fDialogMenu ;
				
				
				mDialogsMenuArray[pDialogId] = fDialogMenu ;
				fDialogMenu.y = Utils.AlignCenter(fDialogMenu.height, mStageHeight) ;
				fDialogMenu.x = Utils.AlignCenter(fDialogMenu.width, mStageWidth) ;
			}
			
			return fDialogMenu ;
		}
		
		/**
		 * @private 
		 */
		protected function OnTextDisplayCompleted(event:Event):void
		{
			var fTextDisplay:SciDialogTextDisplay = event.target as SciDialogTextDisplay ;
			//trace("SciDialogController OnTextDisplayCompleted");
			
			if( fTextDisplay == null)
				return ;
				
			fTextDisplay.removeEventListener(Event.COMPLETE,OnTextDisplayCompleted);
			
			if(this.contains( fTextDisplay ) )
				this.removeChild(fTextDisplay);
			
			if(mOnCharacterSayCompleted != null)
				mOnCharacterSayCompleted();
		}
		
		/**
		 * @private
		 */		
		protected function OnDisplayInfoCompleted(event:Event):void
		{
			OnTextDisplayCompleted(event);
			mGuiMngr.enabled = true ;
			mSceneMngr.enabled = true ;
		}
		
	
		
		/**
		 * @private
		 */
		private function OnDialogOptionSelected(event:TextSelectedEvent):void
		{
			//trace("OnDialogOptionSelected");
			var fTopic:Topic = event.topic ;
			PlayTopic(fTopic, OnTopicSayCompleted);
			
		}
		
		/**
		 * @private
		 */
		private function OnTopicSayCompleted():void
		{
			if(!(mCurrentSayIterator.hasNext()))
			{
				SetDialogPanelVisible(true) ;
				RunAction(mPlayingTopic);
				mPlayingTopic = null ;
				return ;
			}
			var fSayItem:SayItem = mCurrentSayIterator.next() as SayItem ;
			var fSpeakerChar:AdventureCharacter = AdventureMaster.CharactersMngr.GetCharacter(fSayItem.speakerId) ;
			CharacterSay(fSpeakerChar, fSayItem.text, OnTopicSayCompleted ); 
			
		}
		
		/**
		 * @private
		 */		
		private function SetDialogPanelVisible(value:Boolean):void
		{
			if(mCurrentDialogMenu != null)
			{
				mCurrentDialogMenu.visible = value ;
			}
		}
		
		/**
		 * 
		 * @inheritDoc 
		 */		
		public function DisplayInfo(pText:String, pOnCompleteFunction:Function = null):void
		{
			if(mCurrentDialog != null)
			{
				mCurrentDialogMenu.removeEventListener( SciDialogMenu.TEXT_SELECTED, OnDialogOptionSelected );
				if(this.contains( mCurrentDialogMenu) )
					this.removeChild(mCurrentDialogMenu);				
			}
			
			
			mGuiMngr.enabled = false ;
			mSceneMngr.enabled = false ;
			
			var fNewText:SciDialogTextDisplay = new SciDialogTextDisplay(pText,null,mConfTextBg,true,mConfDTextFont,mConfDTextSize,mConfTextInfoColor,mConfDTextBold);
			
			mOnCharacterSayCompleted = pOnCompleteFunction ;
			
			fNewText.bgColor = mConfTextDisplayColor ;
			fNewText.SetSize( mConfTDisplayWidth, mConfTDisplayHeight);
						
			fNewText.addEventListener(Event.COMPLETE,OnDisplayInfoCompleted,false,0,true);
			this.addChild( fNewText );
			fNewText.leftMargin = mConfDTextLeftMargin ;
			fNewText.topMargin = mConfDTextTopMargin ;
			
			fNewText.x = Utils.AlignCenter(fNewText.width, mStageWidth);
			fNewText.y = mConfTextYCoordinate ;			
		}
	
		
		public function SetOptionVisible(pDialogId:String, pTopicId:String, value:Boolean):void
		{
			
			CreateDialogMenu(pDialogId);
			var fDMenu:SciDialogMenu = mDialogsMenuArray[pDialogId] ;
			if(fDMenu == null)
			{
				return ;
			}
			
			fDMenu.SetOptionVisible(pTopicId,value);
			UpdateScrollButtons();
			
			
		}
		
		public function UpdateScrollButtons():void
		{
			
		}
		
		
	}
}